#ifndef __LDX_SMATERIAL_H_INCLUDE__
#define __LDX_SMATERIAL_H_INCLUDE__
#include "LDXConfig.h"
#include "EMaterialFlags.h"
#include "SColorf.h"
#include "SMaterialLayer.h"

namespace ldx
{
	namespace render
	{
		const int MAX_TEXTURE_LAYER_COUNT = __MAX_TEXTURE_LAYER_COUNT;
		enum E_MATERIAL_TYPE
		{
			EMT_NONE = 0,
			EMT_SINGLE_COLOR = 1,
			EMT_SD_PHONG,
			EMT_SKY_BOX,
			EMT_SD_TERRAIN_PHONG,
			EMT_SIMPLE_CLOUD,

		};

		const char* const sBuiltInMaterialTypeNames[] =
		{
			"none",
			"single_color",
			"sd_phong",
			"sky_box",
			"sd_terrain_phong",
			"simple_cloud",
		};

		class SMaterial
		{
		public:
			SMaterial()
				:MaterialType(EMT_NONE),
				AmbientColor(0.3f, 0.3f, 0.3f, 0.3f),
				DiffuseColor(0.3f, 0.3f, 0.3f, 0.3f),
				EmissiveColor(0.f, 0.f, 0.f, 0.f),
				SpecularColor(1.f, 1.f, 1.f, 1.f),
				Shininess(70.f),
				Wireframe(false),
				PointCloud(false),
				Lighting(true),
				ZWriteEnable(true),
				BackfaceCulling(true),
				FrontfaceCulling(false),
				FogEnable(false),
				UseMipMaps(true)
			{
				for (mt::uint i = 0; i < E_TEXTURE_LAYER_TYPE::ETLT_COUNT; ++i)
				{
					IsLayerUsed[i] = false;
				}
			}

			bool operator==(const SMaterial& other)const
			{
				return MaterialType == other.MaterialType&&
					AmbientColor == other.AmbientColor&&
					DiffuseColor == other.DiffuseColor&&
					EmissiveColor == other.EmissiveColor&&
					SpecularColor == other.SpecularColor&&
					Shininess == other.Shininess&&
					Wireframe == other.Wireframe&&
					PointCloud == other.PointCloud&&
					Lighting == other.Lighting&&
					ZWriteEnable == other.ZWriteEnable&&
					BackfaceCulling == other.BackfaceCulling&&
					FrontfaceCulling == other.FrontfaceCulling&&
					FogEnable == other.FogEnable&&
					UseMipMaps == other.UseMipMaps;
			}

			bool operator!=(const SMaterial& other) const
			{
				return !(*this == other);
			}

			void setFlag(E_MATERIAL_FLAG flag, bool value)
			{
				switch (flag)
				{
				case ldx::render::EMF_WIREFRAME:
					break;
				case ldx::render::EMF_POINTCLOUD:
					break;
				case ldx::render::EMF_GOURAUD_SHADING:
					break;
				case ldx::render::EMF_LIGHTING:
					Lighting = value;
					break;
				case ldx::render::EMF_ZBUFFER:
					break;
				case ldx::render::EMF_ZWRITE_ENABLE:
					break;
				case ldx::render::EMF_BACK_FACE_CULLING:
					break;
				case ldx::render::EMF_FRONT_FACE_CULLING:
					break;
				case ldx::render::EMF_BILINEAR_FILTER:
					break;
				case ldx::render::EMF_TRILINEAR_FILTER:
					break;
				case ldx::render::EMF_ANISOTROPIC_FILTER:
					break;
				case ldx::render::EMF_FOG_ENABLE:
					break;
				case ldx::render::EMF_NORMALIZE_NORMALS:
					break;
				case ldx::render::EMF_TEXTURE_WRAP:
					break;
				case ldx::render::EMF_ANTI_ALIASING:
					break;
				case ldx::render::EMF_COLOR_MASK:
					break;
				case ldx::render::EMF_COLOR_MATERIAL:
					break;
				case ldx::render::EMF_USE_MIP_MAPS:
					break;
				case ldx::render::EMF_BLEND_OPERATION:
					break;
				case ldx::render::EMF_POLYGON_OFFSET:
					break;
				default:
					break;
				}
			}

			void setLayerUsed(bool isused, E_TEXTURE_LAYER_TYPE type)
			{
				IsLayerUsed[type] = isused;
			}
			
			//! Set flags for material into uint value.
			/** flagA,flagB:for texture layers.;flagC, flagD:for other tags.
			* flagC:...1:fogEnable,0:lighting.
			*/
			void setFlags(mt::uint& flagA, mt::uint& flagB,mt::uint& flagC)
			{
				flagA = flagB = flagC  = 0;
				mt::uint tag = 0x1;
				int i;
				for (i = 0; i < 32&&i<E_TEXTURE_LAYER_TYPE::ETLT_COUNT; ++i)
				{
					if (IsLayerUsed[i])
						flagA |= tag;
					tag = tag<< 1;
				}
				tag = 0x1;
				for (i = 32; i < 64 && i<E_TEXTURE_LAYER_TYPE::ETLT_COUNT; ++i)
				{
					if (IsLayerUsed[i-32])
						flagB |= tag;
					tag = tag << 1;
				}
				//other flags
				if (Lighting)
				{
					flagC |= 0x1;
				}
				if (FogEnable)
					flagC |= 2;
			}

			bool isTextured()
			{
				for (int i = 0; i < ETLT_COUNT; ++i)
				{
					if (IsLayerUsed[i] != false)
						return true;
				}
				return false;
			}

			E_MATERIAL_TYPE MaterialType;

			//! global light
			SColorf AmbientColor;

			//! diffuse light
			SColorf DiffuseColor;

			//! emitted light
			SColorf EmissiveColor;

			//! specular light
			SColorf SpecularColor;

			//! Texture layer.
			SMaterialLayer TextureLayer[E_TEXTURE_LAYER_TYPE::ETLT_COUNT];

			//! used layer
			bool IsLayerUsed[E_TEXTURE_LAYER_TYPE::ETLT_COUNT];

			//! Shininess
			float Shininess;

			//! for line or point
			float Thickness;

			//!
			//mt::ushort zBuffer;

			//mt::ushort AntiAliasing;

			//mt::ushort ColorMask;

			//mt::ushort ColorMaterial;

			//! Draw as wireframe.false
			bool Wireframe;

			//! Draw as point;false
			bool PointCloud;

			//! Is lighting,false
			bool Lighting;

			//! Is zbuffer enable,true
			bool ZWriteEnable;

			//! Is backface culling,true
			bool BackfaceCulling;

			//! Is front face culling,false
			bool FrontfaceCulling;

			//! Is fog enable,false
			bool FogEnable;

			//! Us mimap,false
			bool UseMipMaps;
		};

		extern SMaterial IdentityMaterial;
	}
}
#endif//! __LDX_SMATERIAL_H_INCLUDE__